using System.Collections;
using System.Collections.Generic;
using System.IO;
using ViScript.Core.Blocks;
using ViScript.Core.Utils;

namespace ViScript.Core
{
    public class SentenceReader : IEnumerable<ISentence>
    {
        private readonly IEscapeStrategy escapeStrategy;
        private readonly string fileName;
        private readonly TextReader textReader;

        public SentenceReader(string fileName)
            : this(fileName, new StreamReader(fileName))
        {
        }

        public SentenceReader(string fileName, TextReader textReader)
            : this(new Base64SerializationBasedEscapeStrategy())
        {
            this.fileName = fileName;
            this.textReader = textReader;
        }

        protected SentenceReader(IEscapeStrategy escapeStrategy)
        {
            this.escapeStrategy = escapeStrategy;
        }

        IEnumerator<ISentence> IEnumerable<ISentence>.GetEnumerator()
        {
            return GetTypedEnumerator();
        }

        public IEnumerator GetEnumerator()
        {
            return GetTypedEnumerator();
        }

        private IEnumerator<ISentence> GetTypedEnumerator()
        {
            string content;
            int lineNumber = 0;
            while ((content = textReader.ReadLine()) != null)
            {
                ++lineNumber;
                string[] sentenceContents = Escape(content).Split('.');
                foreach (string sentenceContent in sentenceContents)
                {
                    Sentence sentence = new Sentence(fileName, lineNumber, sentenceContent);
                    if (sentence.TrimmedContent.Length > 0)
                    {
                        yield return sentence;
                    }
                }
            }
        }

        public virtual string Escape(string content)
        {
            RootBlock rootBlock = new RootBlock(escapeStrategy);
            foreach (char c in content)
            {
                rootBlock.Append(c);
            }
            return rootBlock.Escape();
        }
    }
}